package com.pengshun.config;

import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * @author luoligang
 * @create 2021/4/10
 */
@Aspect
@Component
@Slf4j
@SuppressWarnings("all")
public class RepeatSubmitAspect {
    public static final String  KEYPREX="noRpeat:user:";

    @Autowired
    private RedisTemplate redisTemplate;

    private static final Cache<String, Object> CACHES = CacheBuilder.newBuilder()
            // 最大缓存 100 个
            .maximumSize(100)
            // 设置缓存过期时间为5S
            .expireAfterWrite(3, TimeUnit.SECONDS)
            .build();

    /**
     * 进行接口防重复操作处理
     * @param pjp
     * @param noRepeatSubmit
     * @return
     */
    @Around("execution(* com.pengshun.modules.api.*.*.*Controller.*(..))&& @annotation(noRepeatSubmit)")
    public Object around(ProceedingJoinPoint pjp, NoRepeatSubmit noRepeatSubmit) throws Throwable {
        MethodSignature signature = (MethodSignature) pjp.getSignature();
        Method method = signature.getMethod();
        NoRepeatSubmit submit = method.getAnnotation(NoRepeatSubmit.class);
        String key = getCacheKey(submit, pjp.getArgs());
        if (!StringUtils.isEmpty(key)) {
            if (CACHES.getIfPresent(key) != null) {
                throw new RuntimeException("当前操作过于频繁！请稍后再试");
            }
            // 如果是第一次请求,就将key存入缓存中
            CACHES.put(key, key);
        }
        try {
            return pjp.proceed();
        } catch (Throwable throwable) {
            System.err.println(throwable);
            throw new RuntimeException("服务器异常");
        } finally {
            //如果演示的话需要注释该代码,手动将缓存清除，实际应该放开
            //CACHES.invalidate(key);
        }

//        try {
//            long aa=new java.util.Random().nextInt(2000) + 1;
//            Thread.sleep(aa);
//            System.out.println("11111111:----"+aa);
//            //获取request
//            HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
//            //拿到token和请求路径
//            StringBuilder sb = new StringBuilder();
//            sb.append(KEYPREX).append(request.getHeader("jwtToken").toString()).append(request.getRequestURI().toString());
//            //获取现在时间
//            long now = System.currentTimeMillis();
//            if (redisTemplate.hasKey(sb.toString())){
//                //上次请求时间
//                long lastTime= Long.valueOf(redisTemplate.opsForValue().get(sb.toString()).toString()) ;
//                // 如果现在距离上次提交时间小于设置的默认时间 则 判断为重复提交  否则 正常提交 -> 进入业务处理
//                if ((now - lastTime)>noRepeatSubmit.lockTime()){
//                    //重新记录时间 10分钟过期时间
//                    redisTemplate.opsForValue().set(sb.toString(),String.valueOf(now),10, TimeUnit.MINUTES);
//                    //处理业务
//                    Object result =  pjp.proceed();
//                    return result;
//                }else {
//                    return new BaseResult(1,"点击的太快了,请慢一点!");
//                }
//            }else {
//                //第一次操作
//                redisTemplate.opsForValue().set(sb.toString(),String.valueOf(now),10, TimeUnit.MINUTES);
//                Object result =  pjp.proceed();
//                return result;
//            }
//        }catch (Throwable e){
//            log.error("校验表单重复提交时异常: {}", e.getMessage());
//            return new BaseResult(1,"校验重复提交时异常");
//        }
    }

    private String getCacheKey(NoRepeatSubmit submit, Object[] args) {
        String prefix = submit.prefix();
        return prefix + args[0];
    }


}
